#! /usr/bin/env python
# coding:utf-8

"""
Usage:
    ed3-local (qq|ios|android) <regid> <rextern> <ridx> <lidx>

Note:
    <regid> 服务器编号(如：qq13服即为13)
    <rextern> 远程服务器外网ip
    <ridx> 远程服务器上的appid
    <lidx> 本地服务器上的appid
"""

import os
import io
import sh
import sys
import json
import string
import shutil
import docopt

def extract(pkg_root, index):
    for file in os.listdir(pkg_root):
        if file.startswith('ed3_app_'):
            path = '/data/app%02d' % index
        elif file.startswith('ed3_exp_'):
            path = '/data/wwwroot/exp%02d' % index
        elif file.startswith('ed3_db_'):
            path = os.path.join(pkg_root, 'ed3.sql')
        else:
            continue

        if os.path.exists(path):
            c = raw_input('path %s already exists, OVERWRITE? [y/n] ' % path)
            if c != 'y':
                raise Exception('extract stoped!')
            shutil.rmtree(path)

        os.makedirs(path)

        tar = os.path.join(pkg_root, file)
        print 'extract %s to %s ...' % (tar, path)
        sh.tar.xf(tar, C=path)

def import_db(sql_file, user, password, db):
    sql = 'drop database if exists %s; create database %s default charset=utf8;' % (db, db)
    sh.mysql('-u' + user, '-p' + password, _in=sql)
    
    sql = 'use %s; source %s;' % (db, sql_file)
    sh.mysql('-u' + user, '-p' + password, _in=sql)

def fix_config(remote, extern, index):
    app_root = '/data/app%02d' % index

    # fix config.json
    conf_path = os.path.join(app_root, './conf_sys/config.json')
    with open(conf_path) as f:
        conf = json.load(f)

    fix_port = lambda port : (index - 1) * 1000 + port
    server_id = conf['server']['server_id']
    chat_port = fix_port(18906)

    conf['login']['http_port'] = fix_port(18082)
    conf['login']['data_url'] = 'http://127.0.0.1:%d' % fix_port(18083)
    conf['login']['data_port'] = fix_port(18908)

    conf['logic']['sock_port'] = fix_port(18906)
    conf['logic']['http_port'] = fix_port(18081)
    conf['logic']['data_url'] = 'http://127.0.0.1:%d' % fix_port(18083)
    conf['logic']['data_port'] = fix_port(18908)

    conf['cache']['sock_port'] = fix_port(18908)
    conf['cache']['http_port'] = fix_port(18083)
    conf['cache']['data_port'] = fix_port(18908)

    conf['logger']['http_port'] = fix_port(18084)
    conf['logger']['data_port'] = fix_port(11315)

    with open(conf_path, 'w') as f:
        json.dump(conf, f, indent=4)

    # fix db.json
    conf_path = os.path.join(app_root, './conf_sys/db.json')
    sh.sed('s/db_\(game\|mail\|expd\|pays\)\(.\{2\}\)/db_\\1%02d/g' % index, conf_path, i=True)

    # fix exp/config/config.inc.php
    exp_root = '/data/wwwroot/exp%02d' % index
    conf_path = os.path.join(exp_root, './config/config.inc.php')

    sh.sed('s/db_\(game\|mail\|expd\|pays\|logs\|gmcs\)\(.\{2\}\)/db_\\1%02d/g' % index, conf_path, i=True)

    sh.sed('s/%s/%s/g' % (remote, extern), conf_path, i=True)
    sh.sed('s/\(%s[^0-9]\+\)\([0-9]\+\)/\\1%02d/g' % (extern, index), conf_path, i=True)

    return server_id, chat_port

def scp_fix(host, user, password, path):
    def wrapper(cb):
        print 'running %s ...' % cb.func_name
        ssh = sh.sshpass.bake('-p' + password, 'ssh', '-o', 'StrictHostKeyChecking=no', '%s@%s' % (user, host), _out=sys.stdout)

        buff = io.StringIO()
        ssh("""ifconfig eth0 | grep "inet addr" | awk -F: '{print $2}' | awk '{print $1}'""", _out=buff)
        local = buff.getvalue()[:-1]

        # fix chat
        scp = sh.sshpass.bake('-p' + password, 'scp', '-o', 'StrictHostKeyChecking=no', '-r')
        scp('%s@%s:%s' % (user, local, path), pkg_root)

        conf = os.path.join(pkg_root, os.path.basename(path))
        cb(conf)

        scp(conf, '%s@%s:%s' % (user, local, os.path.dirname(path)))
    return wrapper
    

def fix_vm_134(region, server_id, rextern, rlocal, extern, local, index):
    host, user, password = '120.131.8.134', 'root', 'eQgC4vj61Z'

    region_name = 'apple' if region == 'ios' else region
    conf_path = '/data/wwwroot/sync_wwwroot/wwwroot/%s/config/callback_config.inc.php' % region_name
    @scp_fix(host, user, password, conf_path)
    def fix_callback_config(conf_path):
        sh.sed(r's/\(td3_game_http_host%s.*\)%s\(.*logic\)\(.*\)"/\1%s\2%02d"/g' %
           (server_id, rextern, extern, index), conf_path, i=True)
        sh.sed(r's/\(db_td3_pays_host%s.*\)%s/\1%s/g' % (server_id, rlocal, local), conf_path, i=True)
        sh.sed(r's/\(db_td3_pays_base%s.*db_pays\)\([0-9]\+\)/\1%02d/g' % (server_id, index), conf_path, i=True)

    @scp_fix(host, user, password, '/data/wwwroot/m/config.ini.php')
    def fix_pay(conf_path):
        sh.sed(r's/\(%d.*\)%s\([^0-9]*\)\([0-9]\+\)/\1%s\2%02d/g' % (server_id, rextern, extern, index), conf_path, i=True)

    @scp_fix(host, user, password, '/data/wwwroot/log_analystics/config/config.inc.php')
    def fix_log(conf_path):
        sh.sed(r"s/\(td3_%s%d_host\).*/\1 = '%s';/g" % (region, opts['<regid>'], local), conf_path, i=True)
        sh.sed(r"s/\(td3_%s%d_base\).*/\1 = 'db_game%02d';/g" % (region, opts['<regid>'], index), conf_path, i=True)

def fix_vm_24(extern, local, chat_port, server_id, index):
    host, user, password = '120.131.8.24', 'root', 'eQgC4vj61Z'

    @scp_fix(host, user, password, '/data/app/conf_sys/client.json')
    def fix_client(conf_path):
        with open(conf_path) as f:
            conf = json.load(f)
            node = conf['client'][str(server_id)]
            node['host'] = extern
            node['port'] = chat_port

        with open(conf_path, 'w') as f:
            json.dump(conf, f, indent=4)

    # fix db_zone
    sql = '''
        USE `db_zone`;
        SELECT `name` from `list` WHERE `sid` = %s;
    ''' % server_id

    ssh = sh.sshpass.bake('-p' + password, 'ssh', '-o', 'StrictHostKeyChecking=no', '%s@%s' % (user, host), _out=sys.stdout)

    buff = io.StringIO()
    ssh.mysql('-ued3', '-pxsj@ed3.good^team*com', _in=sql, _out=buff)
    server_name = buff.getvalue().splitlines()[1]

    get_url = lambda server : 'http://%s/%s%02d' % (extern, server, index)
    chat_url = 'http://%s:%d' % (extern, chat_port)

    sql = '''
        USE db_zone;
        REPLACE `list`(`sid`, `name`, `expd`, `chat`, `login`, `game`, `logs`, `state`, `ip_in`, `ip`, `flag`)
        VALUES(%d, "%s", "%s", "%s", "%s", "%s", "%s", 2, "%s", "%s", 0);
    ''' % (
        server_id, server_name, get_url('exp'), chat_url, get_url('login'), get_url('logic'),
        get_url('logger'), local, extern)

    sql = sql.encode('utf-8')
    ssh.mysql('-ued3', '-pxsj@ed3.good^team*com', _in=sql)

if __name__ == '__main__':
    proj_root = os.path.abspath(os.path.dirname(__file__))
    pkg_root = os.path.join(proj_root, 'ed3.pkg')

    opts = docopt.docopt(__doc__)
    opts['<ridx>'] = string.atoi(opts['<ridx>'])
    opts['<lidx>'] = string.atoi(opts['<lidx>'])
    opts['<regid>'] = string.atoi(opts['<regid>'])

    conf = {
        'user': 'ed3',
        'password': 'xsj@ed3.good^team*com',
    }

    sh.yum.install('-y', 'sshpass')

    ssh = sh.sshpass.bake('-peQgC4vj61Z', 'ssh', '-o', 'StrictHostKeyChecking=no', 'root@' + opts['<rextern>'], _out=sys.stdout)
    ssh.easy_install('sh', 'docopt')

    buff = io.StringIO()
    ssh("""ifconfig eth0 | grep "inet addr" | awk -F: '{print $2}' | awk '{print $1}'""", _out=buff)
    rlocal = buff.getvalue()[:-1]

    scp = sh.sshpass.bake('-peQgC4vj61Z', 'scp', '-o', 'StrictHostKeyChecking=no', '-r')
    scp(proj_root, 'root@%s:/root' % rlocal)

    buff = io.StringIO()
    sh.curl('http://ident.me', _out=buff)
    extern = buff.getvalue()

    buff = io.StringIO()
    sh.awk(sh.xargs(sh.grep(sh.grep(sh.ifconfig(), 'inet '), '-v', '127.0')), '-F', '[ :]', '{print $3}', _out=buff)
    local = buff.getvalue()[:-1]

    ssh.python('./ed3.move/ed3-remote', local, opts['<ridx>'])

    extract(pkg_root, opts['<lidx>'])

    for path, _, files in os.walk(os.path.join(pkg_root, 'ed3.sql')):
        for f in files:
            file = os.path.join(path, f)
            db = f[:-6] + '%02d' % opts['<lidx>']
            print 'import %s to %s ...' % (file, db)
            import_db(file, conf['user'], conf['password'], db)

    server_id, chat_port = fix_config(opts['<rextern>'], extern, opts['<lidx>'])

    for reg in ('qq', 'ios', 'android'):
        if opts[reg]:
            region = reg
            break

    print 'fix vm 120.131.8.134...'
    fix_vm_134(region, server_id, opts['<rextern>'], rlocal, extern, local, opts['<lidx>'])

    print 'fix vm 120.131.8.24...'
    fix_vm_24(extern, local, chat_port, server_id, opts['<lidx>'])

    print '\033[1;35m[NOTE]: chat port = %d\033[m' % chat_port
